package org.jeecg.modules.balance.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.Jeepay;
import com.jeequan.jeepay.JeepayClient;
import com.jeequan.jeepay.exception.JeepayException;
import com.jeequan.jeepay.model.PayOrderCreateReqModel;
import com.jeequan.jeepay.request.PayOrderCreateRequest;
import com.jeequan.jeepay.response.PayOrderCreateResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.config.wlhy.JeepayConfig;
import org.jeecg.modules.balance.entity.WlhyBalanceIncomeExpance;
import org.jeecg.modules.balance.mapper.WlhyBalanceIncomeExpanceMapper;
import org.jeecg.modules.balance.service.IWlhyBalanceIncomeExpanceService;
import org.jeecg.modules.order.entity.WlhyOrder;
import org.jeecg.modules.order.service.IWlhyOrderService;
import org.jeecg.modules.system.api.SystemApi;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.jeecg.common.constant.WlhyBizConstant.*;

/**
 * @Description: 钱包收支明细表
 * @Author: jeecg-boot
 * @Date: 2024-04-18
 * @Version: V1.0
 */
@Service
@Slf4j
public class WlhyBalanceIncomeExpanceServiceImpl extends ServiceImpl<WlhyBalanceIncomeExpanceMapper, WlhyBalanceIncomeExpance> implements IWlhyBalanceIncomeExpanceService {


    @Resource
    IWlhyOrderService wlhyOrderService;
    @Resource
    SystemApi systemApi;


    @Override
    public JSONObject charge(String chargeMode, BigDecimal balance,String returnUrl) {
        if (balance.compareTo(BigDecimal.ONE)<0) {
            throw new RuntimeException("充值金额必须大于1元");

        }
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if (!Arrays.asList(WAY_CODE_ALI_PC, WX_NATIVE).contains(chargeMode)) {
            throw new RuntimeException("暂不支持当前支付方式");
        }

        LocalDateTime expireTime = LocalDateTime.now().plusMinutes(JEEPAY_EXPIRE_TIME);
        JSONObject bizData = new JSONObject();
        bizData.put("bizType", ORDER_BIZ_TYPE1);
        bizData.put("balance", balance);
        String orderNo = WlhyOrder.generatorOrderNo();
        WlhyOrder wlhyOrder = new WlhyOrder()
                .setUserId(loginUser.getId())
                .setUserPhone(loginUser.getPhone())
                .setOrderNo(orderNo)
                .setMchno(Jeepay.mchNo)
                .setAppId(Jeepay.appId)
                .setWayCode(chargeMode)
                .setAmount(balance)
                .setClientIp(SpringContextUtils.getHttpServletRequest().getRemoteHost())
                .setSubject("钱包充值")
                .setBody("钱包充值")
                .setExpiredTime(Date.from(expireTime.atZone(ZoneId.systemDefault()).toInstant()))
                .setChannelExtra("")
                .setDivisionMode(DIVISION_MODE0)
                .setExtParam("")
                .setReqTime(new Date())
                .setNotifyUrl(GATEWAY_HOST + "/finance-api/balance/wlhyBalanceIncomeExpance/balanceChargeNotify")
                .setReturnUrl(returnUrl)
                .setOrderState(ORDER_STATE0)

                .setSuccessTime(null)
                .setBizType(ORDER_BIZ_TYPE1)
                .setBizData(JSONObject.toJSONString(bizData));

        /*if (WAY_CODE_ALI_PC.equals(chargeMode)) {
        } else if(WX_NATIVE.equals(chargeMode)) {
            wlhyOrder  .setNotifyUrl(GATEWAY_HOST + "/finance-api/balance/wlhyBalanceIncomeExpance/wxBalanceChargeNotify");
        }*/
        // 创建客户端
        JeepayClient jeepayClient = JeepayClient.getInstance(Jeepay.appId, Jeepay.apiKey);

        // 构建请求数据
        // 支付方式
        PayOrderCreateRequest request = new PayOrderCreateRequest();
        PayOrderCreateReqModel model = new PayOrderCreateReqModel();
        model.setMchNo(Jeepay.mchNo);                       // 商户号
        model.setAppId(jeepayClient.getAppId());            // 应用ID

        model.setMchOrderNo(wlhyOrder.getOrderNo());                       // 商户订单号
        model.setWayCode(chargeMode);                          // 支付方式
        model.setAmount(wlhyOrder.getAmount().multiply(new BigDecimal(100)).longValue());                                // 金额，单位分
        model.setCurrency(JEEPAY_CURRENCY);                           // 币种，目前只支持cny
        model.setClientIp(wlhyOrder.getClientIp());                 // 发起支付请求客户端的IP地址
        model.setSubject(wlhyOrder.getSubject());                         // 商品标题
        model.setBody(wlhyOrder.getBody());                            // 商品描述
        model.setNotifyUrl(wlhyOrder.getNotifyUrl());      // 异步通知地址
        model.setReturnUrl(wlhyOrder.getReturnUrl());                             // 前端跳转地址
        model.setExpiredTime(String.valueOf(Duration.ofMinutes(JEEPAY_EXPIRE_TIME).toSeconds()));                             // 失效时间 秒
        model.setChannelExtra(wlhyOrder.getChannelExtra());       // 渠道扩展参数
        model.setDivisionMode(Byte.valueOf(wlhyOrder.getDivisionMode()));       // 渠道扩展参数
        model.setExtParam(wlhyOrder.getExtParam());                              // 商户扩展参数,回调时原样返回

        request.setBizModel(model);
        // 发起统一下单
        try {
            PayOrderCreateResponse response = jeepayClient.execute(request);
            // 验证返回数据签名
            log.info("验证返回数据签名 {}", response.checkSign(Jeepay.apiKey));
            // 判断下单是否返回成功
            boolean success = response.isSuccess(Jeepay.apiKey);
            if (success) {
                wlhyOrder.setOrderState(ORDER_STATE1)
                        .setPayDataType(response.getData().toJSONString())
                        .setErrCode(response.getCode().toString())
                        .setErrMsg(response.getMsg())
                ;
                wlhyOrderService.save(wlhyOrder);
                return response.getData();
            } else {
                wlhyOrder
                        .setPayDataType(response.getData().toJSONString())
                        .setErrCode(response.getCode().toString())
                        .setErrMsg(response.getMsg())
                ;
                wlhyOrderService.save(wlhyOrder);
                String error = String.format("下单失败,%s", response.getMsg());
                log.info(error);
                throw new RuntimeException(error);
            }
        } catch (JeepayException e) {
            throw new RuntimeException(e.getMessage());
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void balanceChargeNotify(Map<String, String[]> param) {
        String state = param.get("state")[0];
        if (!ORDER_STATE2.equals(state)) {
            log.error("只处理成功的订单 {}",param);

            return;
        }
        String mchOrderNo = param.get("mchOrderNo")[0];
        if (StringUtils.isBlank(mchOrderNo)) {
            log.error("订单号为空 {}",param);
            return;
        }
        WlhyOrder wlhyOrder =  wlhyOrderService.getByOrderNo(mchOrderNo);
        if (null == wlhyOrder) {
            log.error("当前订单不存在 {}",param);
            return;
        }
        if (!ORDER_STATE1.equals(wlhyOrder.getOrderState())) {
            log.info("当前订单已被处理");// 如果不是支付中，说明当前订单已被处理
            return;
        }
        wlhyOrder.setSuccessTime(new Date());
        wlhyOrder.setOrderState(ORDER_STATE2);
        wlhyOrderService.updateById(wlhyOrder);

        BigDecimal balance = JSONObject.parseObject(wlhyOrder.getBizData()).getBigDecimal("balance");
        // 添加收支
        WlhyBalanceIncomeExpance incomeExpance = new WlhyBalanceIncomeExpance()
                .setUserId(wlhyOrder.getUserId())
                .setBalance(balance)
                .setIeType(IE_TYPE1)
                .setIeBizType(IE_BIZ_TYPE1)
                .setSubject("钱包充值")
                .setBody(String.format("钱包充值%s元",balance))
                .setExtParam(wlhyOrder.getId())
                ;
        save(incomeExpance);
        // 更新余额
        Boolean updateBalance = systemApi.updateBalance(wlhyOrder.getUserId(), true, balance);
        if (!updateBalance) {
            log.info("更新余额失败");
            throw new RuntimeException("更新余额失败");
        }

    }

}
